// 方法的enum
enum methods { getAll, get, set, remove, clear }

/* 
@params
1. nameSpace:string 对象名称，默认没有
2. isPromise:boolean 是否是异步的promise模式，默认是true
 */
let createStore = function (nameSpace: string | undefined = undefined, isPromise: boolean = false): $store2 {

  // 默认为promise模式，每次执行判断是否是promise的主方法
  store2.isPromise = isPromise
  store2.nameSpace = nameSpace ? nameSpace + '.' : undefined
  function store2(key: anyObj | string | boolean | undefined = undefined, data: Function | string | anyObj | undefined = undefined): Promise<any> | any {
    // 返回一个外包装的promise
    // 注意这一行会导致一些判断上的错误，现在已经修复
    if (!!key && !!nameSpace) {
      key = store2.nameSpace ? store2.nameSpace + key : key
    }
    if (store2.isPromise) {
      return new Promise((reso, rej) => {
        return processStore({ reso, rej, key, data })
      })
    } else {
      return processStore({ key, data })
    }
  }

  // 去保存的核心方法，主要作用是根据参数的类型以及数量来重载方法，以后重写记得传荣arguments的元素数量来简化
  function processStore({ reso = undefined, rej = undefined, key = '', data = '' }: $processStoreParams = {}) {
    // 如果是promise模式
    // console.log('promise', store2.isPromise, 'key', key, 'data', data, 'reso', reso, 'rej', rej)
    if (store2.isPromise && reso && rej) {
      switch (true) {
        // 不存在任何参数
        case !key && !data && key !== false:
          toStore({ reso, rej, way: methods.getAll })
          break
        // 只存在一个参数
        case (!!key && !data) || (key === false && !data):
          switch (true) {
            // 如果是false则删除所有的
            case key === false:
              toStore({ reso, rej, way: methods.clear })
              break
            // 如果是字符串，那么应该是获取某个值
            case typeof key === 'string':
              toStore({ reso, rej, way: methods.get, key: <string>key })
              break
            // 如果是对象则对其惊醒逐个保存
            case typeof key === 'object':
              let storeArr = []
              // 进行promise的存储
              for (let item in <anyObj>key) {
                storeArr.push(singleStore(item, (<anyObj>key)[item]))
              }
              Promise.all(storeArr).then(res => { reso(res) }).catch(err => { rej(err) })
          }
          break;
        case !!key && !!data:
          // console.log(`key`, key, 'data', data)
          // 如果data是处理函数则先运行处理
          if (Object.prototype.toString.call(data).includes('Function')) {
            toStore({ reso, rej, way: methods.set, key: <string>key, data: data() })
          } else {
            toStore({ reso, rej, way: methods.set, key: <string>key, data })
          }
          break
        default:
          console.log(`default`)
      }
    } else {//如果是同步的方法
      // console.log(`else`)
      switch (true) {
        // 不存在参数，则全部返回
        case !key && !data && key !== false:
          return wx.getStorageInfoSync()
          break
        case (!!key && !data) || (key === false && !data):
          switch (true) {
            case key == false:
              return wx.clearStorageSync()
              break
            case typeof key == 'string':
              var _data = wx.getStorageSync(<string>key)
              if (_data) {
                return _data
              } else {
                return false
              }
              break
            case typeof key === 'object':
              for (let item in <anyObj>key) {
                wx.setStorageSync(item, (<anyObj>key)[item])
              }
          }
        case !!key && !!data:
          if (Object.prototype.toString.call(data).includes('Function')) {
            wx.setStorageSync(<string>key, data())
          } else {
            wx.setStorageSync(<string>key, data)
          }
          break;

      }
    }
  }

  // 实际去存储的方法，根据不同的类型调用不同的wx的方法
  //主要用作promise部分
  function toStore(zw: $toStore) {
    // console.log(`store`, zw)
    switch (zw.way) {
      case methods.get:
        wx.getStorage({
          key: <string>zw.key,
          success(res: any) {
            zw.reso(res.data)
          },
          fail(err: $wxErr) {
            if (err.errMsg == 'getStorage:fail data not found') {
              zw.reso(false)
            } else {
              zw.rej(err)
            }
          }
        })
        break
      case methods.set:
        wx.setStorage({
          key: <string>zw.key,
          data: zw.data,
          success(res: any) { zw.reso(res) },
          fail(err: Error) { zw.rej(err) }
        })
        break
      case methods.remove:
        wx.removeStorage({
          key: <string>zw.key,
          success(res: any) { zw.reso(res) },
          fail(err: Error) { zw.rej(err) }
        })
        break;
      case methods.clear:
        wx.clearStorage({
          success(res: any) { zw.reso(res) },
          fail(err: Error) { zw.rej(err) }
        })
        break;
      case methods.getAll:
        wx.getStorageInfo({
          success(res: any) {
            let o: anyObj = {}
            for (const item of res.keys) {
              o[item] = wx.getStorageSync(item)
            }
            Object.assign(o, res)
            zw.reso(o)
          },
          fail(err: Error) { zw.rej(err) }
        })
        break;
      default:
        throw new Error('参数错误')
    }
  }

  // 单个存储的promise页面,用来存储对象方式的，调用Promise.all用。
  function singleStore(key: string, data: anyObj | string) {
    return new Promise((reso, rej) => {
      wx.setStorage({
        key,
        data,
        success(res: any) { reso(res) },
        fail(err: Error) { rej(err) }
      })
    })
  }

  // 其他的方法
  let othersMethods = {
    get(key: string) {
      return store2(key)
    },
    set(key: string, data: string | anyObj) {
      return store2(key, data)
    },
    transact(key: string, data: Function) {
      return store2(key, data)
    },
    clear() {
      return store2(false)
    },
    has(key: string) {
      return !!wx.getStorageSync(key)
    },
    remove(key: string) {
      if (store2.isPromise) {
        return new Promise((reso, rej) => {
          toStore({ reso, rej, way: methods.remove, key })
        })
      } else {
        return wx.removeStorageSync(key)
      }
    },
    getAll() {
      let o: anyObj = {}
      let c = wx.getStorageInfoSync()
      for (const item of c.keys) {
        o[item] = wx.getStorageSync(item)
      }
      return Object.assign(o, c)
    },
    add(key: string, data: any) {
      return store2(key, data)
    },
    keys() {
      return wx.getStorageInfoSync().keys
    },
    size() {
      return wx.getStorageInfoSync().keys.length
    },
    clearAll() {
      return store2(false)
    }
  }

  // 设置是否是promise风格的,isPromise=true是|false不是
  store2.create = createStore

  // 赋值
  Object.assign(store2, othersMethods)
  return <$store2>store2
}
// 关于是否是同步的说明和使用方法
/* 
如果是异步的那么可以使用promise风格，如果是同步的那么直接写下一步的代码就行
 */
let mjStore = createStore()

export default mjStore
export {
  mjStore
}
